﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
using FrontEndDL = MSAS.FrontEnd.DL;
using System.Configuration;
using System.Data.Linq;
using WEX.Logging.Interop;
using System.Globalization;


namespace Microsoft.Reputation.Tests.FrontEndCommon
{
    public class ConfidenceBag
    {
        public string catID { get; set; }
        public string conf { get; set; }
        public string hostI { get; set; }
        public string pathI { get; set; }
    }

    public class TestDataInjector
    {
        private static string connStr = ConfigurationSettings.AppSettings["SDB_ConnectionString"];
        public long maxObjLookup { get; set; }
        public long maxObj { get; set; }


        /// <summary>
        /// Creates one entry in the WebService.Object table for the packed object provided
        /// </summary>
        /// <param name="sha256">SHA256 in hexbinary - primary key in WebService.Object table</param>
        /// <param name="binaryPack">Reputation data as a Binary Pack</param>
        /// <param name="type">Object Type, eg: URL = 4</param>
        /// <param name="version">Version Id for the object</param>
        public static void InjectObjectData(byte[] sha256, byte[] binaryPack, uint type, long version)
        {
            using (FrontEndDL.ServiceDataContext db = new FrontEndDL.ServiceDataContext(connStr))
            {
                db.Objects.InsertOnSubmit(new FrontEndDL.Object
                {
                    SHA256 = sha256,
                    ReputationBinary = binaryPack,
                    ObjectTypeId = (short)type,
                    ObjectVersionId = BitConverter.GetBytes(version).Reverse().ToArray(),
                });

                db.SubmitChanges();
            }
        }

        /// <summary>
        /// Inserts an override entry in the Overrides table. This does not update the Object table with new reputation.
        /// </summary>
        /// <param name="sha">Hash of the object for which the override needs to be created</param>
        /// <param name="version">Version of the object to be inserted</param>
        /// <param name="creationTime">Time of creation of override</param>
        /// <param name="expiration">Time when the override should expire</param>
        /// <param name="type">Object type for which override is created, eg: URL = 4</param>
        /// <returns>Last override Id at which the override entry is created</returns>
        public static long InjectOverrideData(byte[] sha, long version, DateTime creationTime, DateTime expiration, uint type)
        {
            using (FrontEndDL.ServiceDataContext db = new FrontEndDL.ServiceDataContext(connStr))
            {
                db.Overrides.InsertOnSubmit(new FrontEndDL.Override
                {
                    ObjectVersionId = BitConverter.GetBytes(version).Reverse().ToArray(),
                    CreatedDT = creationTime,
                    ExpirationDT = expiration,
                    SHA256 = sha,
                    ObjectTypeId = (short)type
                });
                db.SubmitChanges();

                return (from rows in db.Overrides select rows).OrderByDescending(col => col.OverrideId).FirstOrDefault().OverrideId;
            }
        }

        /// <summary>
        /// Inserts an override entry in the Overrides table for ObjectType = URL and creation Time = UtcNow. 
        /// This does not update the Object table with new reputation.
        /// </summary>
        /// <param name="sha">Hash of the object for which the override needs to be created</param>
        /// <param name="version">Version of the object to be inserted</param>
        /// <param name="expiration">Time when the override should expire</param>
        public static long InjectOverrideData(byte[] sha, long version, DateTime expiration)
        {
            return InjectOverrideData(sha, version, DateTime.UtcNow, expiration, MrsObjectTypes.Url);
        }

        /// <summary>
        /// Updates the Reputation Binary data for the object in WebService.Object table. 
        /// Primary use is to update object entry when override needs to be created.
        /// </summary>
        /// <param name="sha">Hash of the object to be updated</param>
        /// <param name="binaryPack">The new ReputationBinary data</param>
        /// <param name="type">Object type</param>
        /// <param name="version">Object version</param>
        public static void UpdateObjectTableWithOverride(byte[] sha256, byte[] binaryPack, uint type, long version)
        {
            using (FrontEndDL.ServiceDataContext db = new FrontEndDL.ServiceDataContext(connStr))
            {
                FrontEndDL.Object obj = (from rows in db.Objects where rows.SHA256 == sha256 select rows).SingleOrDefault();
                if (null == obj)
                {
                    db.Objects.InsertOnSubmit(new FrontEndDL.Object
                    {
                        SHA256 = sha256,
                        ReputationBinary = binaryPack,
                        ObjectTypeId = (short)type,
                        ObjectVersionId = BitConverter.GetBytes(version).Reverse().ToArray(),
                    });
                }
                else
                {
                    obj.ReputationBinary = binaryPack;
                    obj.ObjectTypeId = (short)type;
                    obj.ObjectVersionId = BitConverter.GetBytes(version).Reverse().ToArray();
                }
                db.SubmitChanges();
            }
        }

        /// <summary>
        /// Deletes the entry from the WebService.Object table for the given SHA
        /// </summary>
        /// <param name="sha">SHA256 value of the object to be deleted</param>
        public static void DeleteTestData(byte[] sha)
        {
            using (FrontEndDL.ServiceDataContext db = new FrontEndDL.ServiceDataContext(connStr))
            {
                var obj = (from rows in db.Objects where rows.SHA256 == sha select rows).SingleOrDefault();
                if(null != obj)
                {
                    db.Objects.DeleteOnSubmit(obj);
                    db.SubmitChanges();
                }
            }
        }

        /// <summary>
        /// Making a separate function for now, so as not to break DeliveryService Function tests. Later on we should move all the code to call the ClearTestData() function and NOT the ClearTable().
        /// BUG 1031 to track this issue.
        /// </summary>
        public void ClearTestData()
        {
            using (FrontEndDL.ServiceDataContext db = new FrontEndDL.ServiceDataContext(connStr))
            {
                db.ExecuteCommand("DELETE FROM WebService.Object;");
            }
        }

        public void ClearOverrides(DateTime expirationTime)
        {
            using (FrontEndDL.ServiceDataContext db = new FrontEndDL.ServiceDataContext(connStr))
            {
                var overrides = db.Overrides.Where(o => o.ExpirationDT == expirationTime).ToList();
                if (overrides.Any())
                {
                    db.Overrides.DeleteAllOnSubmit(overrides);
                    db.Objects.DeleteAllOnSubmit(overrides.Select(o => o.Object));
                }
                db.SubmitChanges();
            }
        }
    }
}
